<?php

abstract class ZFPainel_RestController extends REST_Controller
{

    const ERROR_METHOD_NOT_ALLOWED = 1001;
    const ERROR_DADO_OBRIGATORIO = 1002;
    const ERROR_MUST_BE_INT = 1101;
    const ERROR_MUST_BE_STRING = 1102;
    const ERROR_MUST_BE_ARRAY = 1103;
    const ERROR_EXCEPTION_MODEL = 1104;
    const ERROR_AUTHENTICATE_INCORRECT_IDENTITY = 2001;
    const ERROR_AUTHENTICATE_INVALID_APPKEY = 2002;
    const PARSER_QUERYSTRING = 1001;
    const PARSER_JSON = 1002;
    const PARSER_XML = 1003;
    const TYPE_INT = 1101;
    const TYPE_INT_NULL = 1102;
    const TYPE_STRING = 1201;
    const TYPE_STRING_NULL = 1202;
    const TYPE_ARRAY = 1301;
    const TYPE_ARRAY_NULL = 1302;
    const TYPE_ARRAY_JOINED_NUMBER = 1303;
    const TYPE_ARRAY_JOINED_NUMBER_NULL = 1304;
    const TYPE_ARRAY_JOINED_STRING = 1305;
    const TYPE_ARRAY_JOINED_STRING_NULL = 1306;

    private $_errorMsg = array(
        self::ERROR_METHOD_NOT_ALLOWED => 'Method not allowed',
        self::ERROR_AUTHENTICATE_INCORRECT_IDENTITY => 'Identidade/Credencial incorreto(s)',
        self::ERROR_AUTHENTICATE_INVALID_APPKEY => 'AppKey invalido para a identidade informada',
    );

    /**
     * @var REST_Response
     */
    protected $_response = null;

    protected function addAviso($avisoCd, $avisoMsg)
    {
        $this->view->avisos[] = array(
            'cd' => $avisoCd,
            'msg' => $avisoMsg,
        );
        $this->view->avisosContador++;
    }

    protected function addAvisos($avisos)
    {
        die('<pre>' . __FILE__ . ' in line ' . __LINE__ . "\n" . print_r($avisos, TRUE));
        foreach ($avisos as $aviso) {
            die('<pre>' . __FILE__ . ' in line ' . __LINE__ . "\n" . print_r($aviso, TRUE));
        }
    }

    protected function addError($cd, $message = NULL, array $extra = array())
    {
        if ($cd instanceof Exception) {
            $this->view->erros[] = array(
                'cd' => $cd->getCode(),
                'msg' => $cd->getMessage(),
                    ) + $extra;

            if ($cd->getPrevious() instanceof Exception) {
                $this->addErro($cd->getPrevious());
            }
        } else {
            $this->view->erros[] = array(
                'cd' => $cd,
                'msg' => $message,
                    ) + $extra;
        }

        $this->view->errosContador++;
    }

    private function _callAction()
    {
        $actName = $this->_getParam('act', null);

        if (null === $actName) {
            $actName = $this->_getParam('id', null);
        }
        if (null === $actName) {
            $this->notAllowed();
            return;
        }

        $action = '_' . $this->_getParam('action') . ucfirst($actName) . 'Action';
        
        if (!method_exists($this, $action)) {
            $this->addError(self::ERROR_METHOD_NOT_ALLOWED, "Invalid method $actName [$action].");
            $this->notAllowed();
        } else {
            try {
                $this->$action();
            } catch (Model_Exception_Validacao $exc) {
                $this->addError($exc, null, array(
                    'validacao' => $exc->getMensagensValidacao(),
                    'info' => $exc->getInfoValidacao(),
                ));
            } catch (Exception $exc) {
                $this->addError(self::ERROR_EXCEPTION_MODEL, $exc->getMessage());
            }
        }
    }

    private function _validateParams(array $data, array $validators)
    {
        foreach ($validators as $k => $v) {
            if (!isset($data[$k])) {
                switch ($v) {
                    case self::TYPE_INT:
                    case self::TYPE_STRING:
                    case self::TYPE_ARRAY:
                    case self::TYPE_ARRAY_JOINED_NUMBER:
                    case self::TYPE_ARRAY_JOINED_STRING:
                        $this->addError(self::ERROR_DADO_OBRIGATORIO, "Valor $k ?? obrigat??rio e n??o foi definido");
                        break;
                }
            } else {
                switch ($v) {
                    case self::TYPE_INT:
                    case self::TYPE_INT_NULL:
                        if (!is_numeric($data[$k])) {
                            $this->addError(self::ERROR_MUST_BE_INT, "Valor $k deve ser INT");
                        }
                        break;
                    case self::TYPE_STRING:
                    case self::TYPE_STRING_NULL:
                        if (!is_string($data[$k])) {
                            $this->addError(self::ERROR_MUST_BE_STRING, "Valor $k deve ser STRING");
                        }
                        break;
                    case self::TYPE_ARRAY:
                    case self::TYPE_ARRAY_NULL:
                        if (!is_array($data[$k])) {
                            $this->addError(self::ERROR_MUST_BE_ARRAY, "Valor $k deve ser ARRAY");
                        }
                        break;
                    case self::TYPE_ARRAY_JOINED_NUMBER:
                    case self::TYPE_ARRAY_JOINED_NUMBER_NULL:
                        if (!preg_match_all('#^([0-9]+)(,[0-9]+)*$#', $data[$k], $params)) {
                            $this->addError(self::ERROR_MUST_BE_STRING, "Valor $k deve ser uma lista de numeros separados por virgula");
                        }
                        break;
                    case self::TYPE_ARRAY_JOINED_STRING:
                    case self::TYPE_ARRAY_JOINED_STRING_NULL:
                        if (!preg_match_all('#^([0-9a-z\-\_]+)(,[0-9a-z\-\_]+)*$#i', $data[$k], $params)) {
                            $this->addError(self::ERROR_MUST_BE_STRING, "Valor $k deve ser uma lista de palavras separados por virgula");
                        }
                        break;
                }
            }
        }

        if ($this->view->errosContador > 0) {
            $this->_response->badRequest();
            return FALSE;
        }
        return TRUE;
    }

    public function init()
    {
        $this->view->erros = array();
        $this->view->errosContador = 0;
        $this->view->avisos = array();
        $this->view->avisosContador = 0;
    }

    public function getAction()
    {
        $this->getRequest()->setParam('action', 'get');
        $this->_callAction();
    }

    public function postAction()
    {
        $this->getRequest()->setParam('action', 'post');
        $this->_callAction();
    }

    public function putAction()
    {
        $this->postAction();
    }

}
